#pragma once
#include<memory>
#include<mutex>
#include<string>
#include<atomic>
#include"level.hpp"
#include"formatter.hpp"
#include"logsink.hpp"
#include <stdarg.h>
#include "asynchwork.hpp"
#include"buffer.hpp"
#include<unordered_map>

namespace CH
{
	//同步或异步
	enum class LoggerType
	{
		LOGGER_SYNCH,//同步
		LOGGER_ASYNCH//异步
	};

	//日志器基类
	class Logger
	{
	public:
		using prt=std::shared_ptr<Logger>;
		Logger(const string& logger_name,LogLevel::value limit_level,Formater::prt& formatter,std::vector<LogSink::prt>& sinks)
			:_logger_name(logger_name),_limit_level(limit_level),_formatter(formatter),_sinks(sinks.begin(),sinks.end())
		{}

		//获取日志器名
		const std::string& logger_name() { return _logger_name;}
		/* 构造日志消息对象过程， 并得到格式化后的日志消息字符串-- 然后进行落地输出*/
		//为什么只需要传入这三个参数？logger_name是成员变量，level是默认等级，其他的都不用用户主动传递
		void debug(const std::string& filename,size_t line,const std::string& fmt,...)
		{
			// 1、判断当前日志等级是否达到输出标准，小于则不输出
			if(LogLevel::value::DEBUG<_limit_level) return;

			// 2、 fmt是格式例："%d%s",会根据fmt的格式从不定参中取对应对字符
			va_list ap;
			va_start(ap, fmt);//使ap指向fmt
			char* ret=nullptr;//定义缓冲区
			int n = vasprintf(&ret, fmt.c_str(), ap);//根据fmt的格式，将可对应的可变参数放入ret缓冲区中
			if(n==-1) {
				cout<<"vasprintf false"<<endl;
				return;
			}
			va_end(ap);//关闭指针，防止内存泄露
			// 3、 构造LogMsg对象
			LogMsg msg(filename,_logger_name,line,LogLevel::value::DEBUG,ret);
			 // 4、 通过格式化工具对LogMsg进行格式化，获得格式化后的日志字符串
			 std::stringstream ss;
    		_formatter->format(ss, msg);//例：[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n
			// 5、 进行日志落地
			log(ss.str().c_str(), ss.str().size());//传入需要输出的字符串和字符串的大小
    		free(ret);   // vasprintf() 内部开辟空间了，是动态申请的，需要我们手动释放
		}
		void info(const std::string& filename,size_t line,const std::string& fmt,...)
		{
			if(LogLevel::value::INFO<_limit_level) return;
			va_list ap;
			va_start(ap, fmt);
			char* ret=nullptr;
			int n = vasprintf(&ret, fmt.c_str(), ap);
			if(n==-1) {
				cout<<"vasprintf false"<<endl;
				return;
			}
			va_end(ap);
			LogMsg msg(filename,_logger_name,line,LogLevel::value::INFO,ret);
			 std::stringstream ss;
    		_formatter->format(ss, msg);
			log(ss.str().c_str(), ss.str().size());
    		free(ret);
		}
		void warn(const std::string& filename,size_t line,const std::string& fmt,...)
		{
			if(LogLevel::value::WARN<_limit_level) return;
			va_list ap;
			va_start(ap, fmt);
			char* ret=nullptr;
			int n = vasprintf(&ret, fmt.c_str(), ap);
			if(n==-1) {
				cout<<"vasprintf false"<<endl;
				return;
			}
			va_end(ap);
			LogMsg msg(filename,_logger_name,line,LogLevel::value::WARN,ret);
			 std::stringstream ss;
    		_formatter->format(ss, msg);
			log(ss.str().c_str(), ss.str().size());
    		free(ret);
		}
		void error(const std::string& filename,size_t line,const std::string& fmt,...)
		{
			if(LogLevel::value::ERROR<_limit_level) return;
			va_list ap;
			va_start(ap, fmt);
			char* ret=nullptr;
			int n = vasprintf(&ret, fmt.c_str(), ap);
			if(n==-1) {
				cout<<"vasprintf false"<<endl;
				return;
			}
			va_end(ap);
			LogMsg msg(filename,_logger_name,line,LogLevel::value::ERROR,ret);
			 std::stringstream ss;
    		_formatter->format(ss, msg);
			log(ss.str().c_str(), ss.str().size());
    		free(ret);
		}
		void fatal(const std::string& filename,size_t line,const std::string& fmt,...)
		{
			if(LogLevel::value::FATAL<_limit_level) return;
			va_list ap;
			va_start(ap, fmt);
			char* ret=nullptr;
			int n = vasprintf(&ret, fmt.c_str(), ap);
			if(n==-1) {
				cout<<"vasprintf false"<<endl;
				return;
			}
			va_end(ap);
			LogMsg msg(filename,_logger_name,line,LogLevel::value::FATAL,ret);
			 std::stringstream ss;
    		_formatter->format(ss, msg);
			log(ss.str().c_str(), ss.str().size());
    		free(ret);
		}

	protected:
		/* 抽象接口完成实际的落地输出 -- 不同的日志器会有不同的实际落地方式 */
		virtual void log(const char* data, size_t len) = 0;
	protected:
		std::mutex _mutex;//定义锁
		std::string _logger_name;//日志器名称
		//由于每一条输出消息，都要与其比较，大于则输出，小与则不输出，所以调用非常频繁，即将其设置为原子级别，减少锁的调用
		std::atomic<LogLevel::value> _limit_level;
		Formater::prt _formatter;//传进来需要输出的格式，格式化模块对象，将LogMsg对象格式化成指定字符串
		std::vector<LogSink::prt> _sinks;//由于落地方向可能不止一种，即使用数组进行管理
	};

	//同步日志器
	class SynchLogger:public Logger
	{
	public:
		SynchLogger(const string& logger_name,LogLevel::value limit_level,Formater::prt& formatter,std::vector<LogSink::prt>& sinks)
			:Logger(logger_name,limit_level,formatter,sinks)
		{}
	protected:
		//将数据通过不同的落地方式，输出
		void log(const char* data,size_t len) override
		{
			std::unique_lock<std::mutex> lock(_mutex);//加锁,等log函数释放后，锁也会自动释放
			if(_sinks.empty()) return;
			for(auto& sink:_sinks)
			{
				sink->log(data,len);
			}
		}
	};

	//异步日志器
	class AsynchLogger:public Logger
	{
	public:
		AsynchLogger(const string& logger_name,LogLevel::value limit_level
			,Formater::prt& formatter,std::vector<LogSink::prt>& sinks)
			:Logger(logger_name,limit_level,formatter,sinks),
			_work(std::make_shared<AsynchWork>(std::bind(&AsynchLogger::realLog, this, std::placeholders::_1)))
			{}
		//将数据放入缓冲区中
		void log(const char* data,size_t len)
		{
			_work->push(data,len);
		}
		//从缓冲区中拿到数据，并且通过不同的落地方式，进行输出
		void realLog(Buffer& buf)
		{
			if(_sinks.empty()) return;
			for(auto& sink:_sinks)
			{
				sink->log(buf.begin(),buf.readAbleSize());
			}
		}
	private:
		AsynchWork::prt _work;
	};

	//日志器建造者——基类
	class LoggerBuilder
	{
	public:
		using prt=std::shared_ptr<LoggerBuilder>;
		LoggerBuilder()
			:_logger_type(LoggerType::LOGGER_SYNCH),_logger_level(LogLevel::value::DEBUG)
		{}
		//将日志器的类型传入其中
		void buildLoggerType(LoggerType type) {_logger_type=type;}
		//将日志器的名字传入其中
		void buildLoggerName(const std::string name) {_logger_name=name;}
		//将日志器的等级传入其中
		void buildLoggerLevel(LogLevel::value level) {_logger_level=level;}
		//将日志器的字符格式传入其中
		void buildLoggerFormatter(const std::string& formatter) {
			_formatter=std::make_shared<Formater>(formatter);
		}
		//将日志器的落地方式传入其中
		template<class SinkType,class...Args>
		void buildLoggerSink(Args...args){
			_sinks.push_back(SinkFactory::create<SinkType>(std::forward<Args>(args)...));
		}
		//建造日志器
		virtual Logger::prt build()=0;
	protected:
		LoggerType _logger_type;			//日志器类型
		std::string _logger_name;			//日志器名字
		LogLevel::value _logger_level;		//日志器等级
		Formater::prt _formatter;			//日志器字符格式
		std::vector<LogSink::prt> _sinks;	//日志器落地方式
	};

	//局部日志器建造者
	class LocalLoggerBuilder:public LoggerBuilder
	{
	public:
		virtual Logger::prt build() override{
			assert(!_logger_name.empty());
			if(_formatter.get()==nullptr){
				_formatter=make_shared<Formater>();
			}
			//如果落地方式为空，则将<StdoutSink>类型放入
			if(_sinks.empty()){
				buildLoggerSink<StdoutSink>();
			}
			//如果为异步
			if(_logger_type==LoggerType::LOGGER_ASYNCH){
				return std::make_shared<AsynchLogger>(_logger_name, _logger_level, _formatter, _sinks);
			}

			return std::make_shared<SynchLogger>(_logger_name,_logger_level,_formatter,_sinks);
		}
	};

	//日志器管理者
	class LoggerManager 
	{
	public:
		//单例模式，将其设置为静态，在调用时只会实例化一次
		static LoggerManager& GetInstance()
		{
			static LoggerManager ret;
			return ret;
		}
		//将日志器添加进来
		void AddLogger(Logger::prt& logger)
		{
			//判断是否存在，存在则不需要添加，直接返回
			if(IsLogger(logger->logger_name())) return;
			std::unique_lock<mutex> lock(_mutex);
			
			_loggers.insert(std::make_pair(logger->logger_name(),logger));
		}
		//判断该日志器是否在其中
		bool IsLogger(const std::string& logger_name)
		{
			
			std::unique_lock<mutex> lock(_mutex);
			cout<<"8"<<endl;
			auto it=_loggers.find(logger_name);
			
			if(it==_loggers.end())
				return false;
			return true;
		}
		//查找日志器
		Logger::prt GetLogger(const std::string& logger_name)
		{
			std::unique_lock<mutex> lock(_mutex);
			auto it=_loggers.find(logger_name);
			if(it==_loggers.end())
				return Logger::prt();
			return it->second;
		}
		//获取默认日志器
		Logger::prt RootLogger()
		{
			return _root_logger;
		}
	private:
		LoggerManager(){
			std::unique_ptr<LoggerBuilder> builder(new LocalLoggerBuilder());
			builder->buildLoggerName("root");
			//构建默认日志器，并且返回
			_root_logger=builder->build();
			_loggers.insert(std::make_pair("root",_root_logger));
		}
	private:
		std::mutex _mutex;					//保证线程安全
		Logger::prt _root_logger;			//默认日志器
		std::unordered_map<std::string,Logger::prt> _loggers;	//将日志器全部放入，统一管理
	};

	//全局日志器建造者
	class GlobalLoggerBuilder:public LoggerBuilder
	{
	public:
		virtual Logger::prt build() override{
			assert(!_logger_name.empty());
			if(_formatter.get()==nullptr){
				_formatter=make_shared<Formater>();
			}
			//如果落地方式为空，则将<StdoutSink>类型放入
			if(_sinks.empty()){
				buildLoggerSink<StdoutSink>();
			}
			Logger::prt _logger;
			//如果为异步
			if(_logger_type==LoggerType::LOGGER_ASYNCH){
				_logger=std::make_shared<AsynchLogger>(_logger_name, _logger_level, _formatter, _sinks);
			}
			else{
				_logger=std::make_shared<SynchLogger>(_logger_name,_logger_level,_formatter,_sinks);
			}
			//将创建的日志器，放入LoggerManager类中进行管理
			LoggerManager::GetInstance().AddLogger(_logger);
			return _logger;
		}
	};
}



